package com.hontlong.baidump3crawler;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.log4j.Logger;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.TagNode;
import org.htmlparser.util.ParserException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import com.wole.commons.string.HtmlCleanerXpathUtil;

public class BaiduMp3Crawler {

	private static final Logger logger = Logger.getLogger(BaiduMp3Crawler.class);

	final static HtmlCleaner cleaner = new HtmlCleaner();

	/**
	 * @param args
	 */
	public static void main(final String[] args) {
		if (logger.isDebugEnabled()) {
			logger.debug("main(String[]) - start");
		}

		final Resource res = new ClassPathResource("baidump3crawler.xml");
		final BeanFactory bf = new XmlBeanFactory(res);
		final BaiduMp3Crawler crawler = (BaiduMp3Crawler) bf.getBean("start");

		crawler.work();

		if (logger.isDebugEnabled()) {
			logger.debug("main(String[]) - end");
		}
	}

	/**
	 * 分析歌手列表函数
	 * 
	 * @throws IOException
	 * @throws ParserException
	 */
	private static List<Map<String, Object>> parserSingerList(final String url) throws IOException {
		TagNode doc = cleaner.clean(new URL(url), "GBK");
		TagNode[] tds =
			HtmlCleanerXpathUtil.xpathArray(doc,
				"/body/div[5]/div[@class='content']/div/table/tbody/tr/td");
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		for (TagNode td : tds) {
			String c = td.getText().toString().trim();
			String[] kv = c.split("\\s*\\.\\s*", 2);
			int idx = Integer.parseInt(kv[0]);
			String name = kv[1];
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("idx", idx);
			map.put("name", name);
			list.add(map);
		}
		return list;
	}

	/**
	 * 分析歌曲页面
	 * 
	 * @throws IOException
	 * @throws MalformedURLException
	 */
	private static List<Map<String, Object>> parserSongList(String url) throws IOException {
		TagNode doc = cleaner.clean(new URL(url), "GBK");
		TagNode[] trs = HtmlCleanerXpathUtil.xpathArray(doc, "/body/div[5]//table/tbody/tr");
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		int idx = 1;
		for (TagNode tr : trs) {
			TagNode[] tds = HtmlCleanerXpathUtil.xpathArray(tr, "/td");
			String name = tds[0].getText().toString().trim();
			String singer = tds[1].getText().toString().trim();
			Map<String, Object> row = new HashMap<String, Object>();
			row.put("idx", idx);
			row.put("name", name);
			row.put("singer", singer);
			list.add(row);
			idx++;
		}
		return list;
	}

	/**
	 * 接口函数
	 * 
	 * @throws IOException
	 */
	private static List<Map<String, Object>> parseTopSong(final String url) throws IOException {
		TagNode doc = cleaner.clean(new URL(url), "GBK");
		TagNode[] trs =
			HtmlCleanerXpathUtil.xpathArray(doc, "/body/div[5]/div[3]/div/table/tbody/tr");
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		for (TagNode tr : trs) {
			TagNode[] tds = HtmlCleanerXpathUtil.xpathArray(tr, "/td");
			int idx = Integer.parseInt(tds[1].getText().toString().trim());
			String name = tds[2].findElementByName("a", false).getAttributeByName("title");
			if (name == null) {
				name = tds[2].getText().toString().trim();
			}
			String singer = tds[3].getText().toString().trim();
			Map<String, Object> row = new HashMap<String, Object>();
			row.put("idx", idx);
			row.put("name", name);
			row.put("singer", singer);
			list.add(row);
		}
		return list;
	}

	private DataSource dataSource;

	private QueryRunner queryRunner;

	private void crawlerSingerList(char flag) {
		String url = "http://list.mp3.baidu.com/top/singer/" + flag + ".html";
		String table = "t_singer_top_all";
		logger.info("url=" + url);
		try {
			List<Map<String, Object>> singers = parserSingerList(url);
			logger.info("parser singer num=" + singers.size());
			Object[][] params = new Object[singers.size()][];
			int i = 0;
			for (Map<String, Object> singer : singers) {
				params[i] = new Object[] { singer.get("idx"), singer.get("name") };
				i++;
			}
			queryRunner.update("delete from " + table + " where flag=?", flag);
			queryRunner.batch("INSERT INTO " + table + " (flag,idx,`name`) VALUES('" + flag
				+ "',?,?)", params);
			logger.info("save table to " + table + " ok");
		} catch (IOException e) {
			logger.error("", e);
		} catch (SQLException e) {
			logger.error("", e);
		}

	}

	private void crawlerSingerTop() {
		String url = "http://list.mp3.baidu.com/top/top200.html";
		String table = "t_singer_top_200";
		logger.info("url=" + url);
		try {
			List<Map<String, Object>> singers = parserSingerList(url);
			logger.info("parser singer num=" + singers.size());
			Object[][] params = new Object[singers.size()][];
			int i = 0;
			for (Map<String, Object> singer : singers) {
				params[i] = new Object[] { singer.get("idx"), singer.get("name") };
				i++;
			}
			queryRunner.update("truncate table " + table);
			queryRunner.batch("INSERT INTO " + table + " (idx,`name`) VALUES(?,?)", params);
			logger.info("save to table " + table + " ok");
		} catch (IOException e) {
			logger.error("", e);
		} catch (SQLException e) {
			logger.error("", e);
		}
	}

	private void crawlerSongList(char flag) {
		String url = "http://list.mp3.baidu.com/top/song/" + flag + ".html";
		String table = "t_mp3_top_all";
		logger.info("url=" + url);
		try {
			List<Map<String, Object>> mp3s = parserSongList(url);
			logger.info("paser url size=" + mp3s.size());
			Object[][] params = new Object[mp3s.size()][];
			int i = 0;
			for (Map<String, Object> mp3 : mp3s) {
				params[i] = new Object[] { mp3.get("idx"), mp3.get("name"), mp3.get("singer") };
				i++;
			}
			queryRunner.update("delete from " + table + " where flag=?", flag);
			queryRunner.batch("INSERT INTO " + table + " (flag,idx,`name`,singer) VALUES('" + flag
				+ "',?,?,?)", params);
			logger.info("save to table " + table + " ok");
		} catch (IOException e) {
			logger.error("", e);
		} catch (SQLException e) {
			logger.error("", e);
		}
	}

	private void crawlerSongTop(String url, String table) {
		logger.info("url=" + url);
		try {
			List<Map<String, Object>> mp3s = parseTopSong(url);
			logger.info("parser mp3 size=" + mp3s.size());
			Object[][] params = new Object[mp3s.size()][];
			int i = 0;
			for (Map<String, Object> mp3 : mp3s) {
				params[i] = new Object[] { mp3.get("idx"), mp3.get("name"), mp3.get("singer") };
				i++;
			}
			queryRunner.update("truncate table " + table);
			queryRunner
				.batch("INSERT INTO " + table + " (idx,`name`,singer) VALUES(?,?,?)", params);
			logger.info("save table " + table + " ok");
		} catch (IOException e) {
			logger.error("", e);
		} catch (SQLException e) {
			logger.error("", e);
		}
	}

	public final DataSource getDataSource() {
		return dataSource;
	}

	public void init() {
		this.queryRunner = new QueryRunner(this.dataSource);
	}

	public final void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	/** 业务主函数 */
	public void work() {
		crawlerSongTop("http://list.mp3.baidu.com/top/top100.html", "t_mp3_top_100");
		crawlerSongTop("http://list.mp3.baidu.com/top/top500.html", "t_mp3_top_500");
		// for (char flag : "ABCDEFGHJKLMNOPQRSTWXYZ0".toCharArray()) {
		// crawlerSongList(flag);
		// }
		// crawlerSingerTop();
		// for (char flag : "ABCDEFGHJKLMNOPQRSTWXYZ0".toCharArray()) {
		// crawlerSingerList(flag);
		// }
	}
}
